package com.babai.config;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.jackson.JsonComponent;

import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * 序列化
 */
@JsonComponent
public class DateFormatConfig {

    private static final Log logger = LogFactory.getLog(DateFormatConfig.class);

    private static String[] pattern =
            new String[]{"yyyy-MM-dd", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.S",
                    "yyyy.MM.dd", "yyyy.MM.dd HH:mm", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm:ss.S",
                    "yyyy/MM/dd", "yyyy/MM/dd HH:mm", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss.S"};

    private static final String YYYY_MM_DD = "yyyy-MM-dd";
    private static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    private static final String HH_MM_SS = "HH:mm:ss";


    /**
     * 序列化
     */
    public static class DateJsonSerializer extends JsonSerializer<Date> {
        @Override
        public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            String pattern = YYYY_MM_DD_HH_MM_SS;
            try {

                /**
                 * 判断当前序列化的是对象还是单个属性值
                 * 1. 如果为对象，则获取字段上的JsonFormat注解中的格式
                 * 2. 如果为单个值，则判断字段上的Temporal注解中的TemporalType.DATE或者TemporalType.TIME
                 * 3. 否则选用默认全长度格式
                 */
                JsonStreamContext outputContext = jsonGenerator.getOutputContext();
                if (outputContext.getCurrentValue() != null) {
                    Class<?> clazz = outputContext.getCurrentValue().getClass();
                    String fieldName = outputContext.getCurrentName();
                    Field field = clazz.getDeclaredField(fieldName);
                    JsonFormat jsonFormat = field.getAnnotation(JsonFormat.class);
                    if (jsonFormat != null) {
                        pattern = jsonFormat.pattern();
                    }
                } else {
                    Class<? extends Date> clazz = date.getClass();
                    if (clazz.getName().equalsIgnoreCase(java.sql.Date.class.getName())) {
                        pattern = YYYY_MM_DD;
                    } else {
                        pattern = YYYY_MM_DD_HH_MM_SS;
                    }
                }
            } catch (Exception e) {
                logger.info("no match format, use default");
            }
            String format = DateFormatUtils.format(date, pattern);
            jsonGenerator.writeString(format);
        }
    }

    public static class LocalDateJsonSerializer extends JsonSerializer<LocalDate> {
        @Override
        public void serialize(LocalDate date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD);
            jsonGenerator.writeString(date.format(formatter));
        }
    }

    public static class LocalDateTimeJsonSerializer extends JsonSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime time, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
            jsonGenerator.writeString(time.format(formatter));
        }
    }

    public static class TimestampJsonSerializer extends JsonSerializer<Timestamp> {
        @Override
        public void serialize(Timestamp time, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
            String source = time.toLocalDateTime().format(formatter);
            jsonGenerator.writeString(source);
        }
    }

    /**
     * 反序列化Date
     */
    public static class DateJsonDeserializer extends JsonDeserializer<Date> {
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
            String source = jsonParser.getText();
            Date date = null;
            try {
                date = DateUtils.parseDate(source, pattern);
            } catch (ParseException e) {
                logger.info("date string serializer error : " + source);
            }
            if (date == null) {
                try {
                    Long aLong = Long.valueOf(source);
                    date = new Date(aLong);
                } catch (NumberFormatException e) {
                    logger.info("date string dserializer error : " + source);
                }
            }
            return date;
        }
    }

    /**
     * 反序列化LocalDate
     */
    public static class LocalDateJsonDeserializer extends JsonDeserializer<LocalDate> {
        @Override
        public LocalDate deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
            String source = jsonParser.getText();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD);
            LocalDate localDate = LocalDate.parse(source, formatter);
            return localDate;
        }
    }

    /**
     * 反序列化LocalDateTime
     */
    public static class LocalDateTimeJsonDeserializer extends JsonDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
            String source = jsonParser.getText();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
            LocalDateTime localDateTime = LocalDateTime.parse(source, formatter);
            return localDateTime;
        }
    }

    public static class TimestampJsonDeserializer extends JsonDeserializer<Timestamp> {
        @Override
        public Timestamp deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
            String source = jsonParser.getText();
            Timestamp timestamp = null;
            try {
                LocalDateTime localDateTime = LocalDateTime.parse(source, DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS));
                timestamp = Timestamp.valueOf(localDateTime);
            } catch (Exception e) {
                try {
                    LocalDate localDate = LocalDate.parse(source, DateTimeFormatter.ofPattern(YYYY_MM_DD));
                    LocalTime localTime = LocalTime.parse("00:00:00", DateTimeFormatter.ofPattern(HH_MM_SS));
                    LocalDateTime dateTime = LocalDateTime.of(localDate, localTime);
                    timestamp = Timestamp.valueOf(dateTime);
                } catch (Exception ex) {
                    logger.info("date deserializer error : " + source);
                }
            }
            return timestamp;
        }
    }

}
